package tpase.client.Handler;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import javafx.scene.control.Label;
import tpase.client.VO.Address;
import tpase.client.VO.Message;
import tpase.client.VO.StatusCode;
import tpase.util.Util;

import java.util.List;
import java.util.Map;

@ChannelHandler.Sharable
public class ClientRegisterHandler extends ChannelInboundHandlerAdapter {
    private String jpbcPath;
    private String paramPath;
    private String publicParamPath;
    private Pairing pairing;
    private String uid;
    private List<byte[]> idList;
    Element x_pwd;
    private List<Element> Y_1iList;

    //debug
    private Address address;
    // 同于线程同步的锁
    private final Object lock;
    private int t;
    private List<Boolean>  isExisting;

    public ClientRegisterHandler(String paramPath, String uid, Element x_pwd, List<byte[]> idList, List<Element> Y_1iList, Address address, Object lock, int t, List<Boolean> isExisting) {
        this.paramPath = paramPath;
        this.uid = uid;
        this.x_pwd = x_pwd;
        this.idList = idList;
        jpbcPath = paramPath + "/a.properties";
        pairing = Util.getPairing(jpbcPath);
        publicParamPath = paramPath + "/publicParam.json";
        this.Y_1iList = Y_1iList;
        this.address = address;
        this.lock = lock;
        this.t = t;
        this.isExisting = isExisting;
    }
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Message request = new Message(StatusCode.REGISTER_REQUEST);
        Map<String, byte[]> map = request.getMap();
        map.put("uid", uid.getBytes());
        map.put("x_pwd", x_pwd.toBytes());
        map.put("idList", Util.toJson(idList).getBytes());

        // debug
        System.out.printf("用户[%s] ----(uid, x_pwd)---> 服务器[%s]：\n\tuid[%s]\n\tx_pwd[%s]\n",
                    uid, address.toString(),uid, x_pwd.toString());

        ctx.writeAndFlush(request);

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Message respond = (Message) msg;
        int statusCode = respond.getStatusCode();
        switch (statusCode) {
            case StatusCode.REGISTER_ALREADY_EXISTING:
                registerAlreadyExisting(ctx, respond);
                break;
            case StatusCode.REGISTER_RESPONSE:
                computeAuth(ctx, respond);
                break;
        }

    }

    private void registerAlreadyExisting(ChannelHandlerContext ctx, Message respond) {
        synchronized (lock) {
            isExisting.set(0, true);
            lock.notifyAll();
        }
        ctx.close();
    }

    private void computeAuth(ChannelHandlerContext ctx, Message msg) {
        synchronized (lock) {
            Element Y_1i = pairing.getGT().newElementFromBytes(msg.getMap().get("Y_1i"));
            Y_1iList.add(Y_1i);
            if (Y_1iList.size() >= t) {
                lock.notifyAll();
            } else {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        ctx.close();
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("exceptionCaught: 发生异常，关闭通道");
        System.out.println(cause.toString());
        ctx.close();
    }
}
